#include "base64.h"
#include "vos_print.h"
#include <stdlib.h>
#include <string.h>
#ifdef THIS_MODULE
#undef THIS_MODULE
#define THIS_MODULE "Algorithm"
#endif
VOS_UINT8 base46_map[] = {'A',
    'B',
    'C',
    'D',
    'E',
    'F',
    'G',
    'H',
    'I',
    'J',
    'K',
    'L',
    'M',
    'N',
    'O',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    'V',
    'W',
    'X',
    'Y',
    'Z',
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g',
    'h',
    'i',
    'j',
    'k',
    'l',
    'm',
    'n',
    'o',
    'p',
    'q',
    'r',
    's',
    't',
    'u',
    'v',
    'w',
    'x',
    'y',
    'z',
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    '+',
    '/'};

VOS_UINT8 *base64_encode(VOS_UINT8 *plain)
{
    VOS_PRINT_INFO("%s", "base64_encode");
    VOS_UINT8 counts = 0;
    VOS_UINT8 buffer[3];
    VOS_UINT8 *cipher = (VOS_UINT8 *)malloc(strlen((char *)plain) * 4 / 3 + 4);
    VOS_UINT32 i = 0, c = 0;

    for (i = 0; plain[i] != '\0'; i++) {
        buffer[counts++] = plain[i];
        if (counts == 3) {
            cipher[c++] = base46_map[buffer[0] >> 2];
            cipher[c++] = base46_map[((buffer[0] & 0x03) << 4) + (buffer[1] >> 4)];
            cipher[c++] = base46_map[((buffer[1] & 0x0f) << 2) + (buffer[2] >> 6)];
            cipher[c++] = base46_map[buffer[2] & 0x3f];
            counts = 0;
        }
    }

    if (counts > 0) {
        cipher[c++] = base46_map[buffer[0] >> 2];
        if (counts == 1) {
            cipher[c++] = base46_map[(buffer[0] & 0x03) << 4];
            cipher[c++] = '=';
        } else {  // if counts == 2
            cipher[c++] = base46_map[((buffer[0] & 0x03) << 4) + (buffer[1] >> 4)];
            cipher[c++] = base46_map[(buffer[1] & 0x0f) << 2];
        }
        cipher[c++] = '=';
    }

    cipher[c] = '\0'; /* string padding character */
    return cipher;
}

VOS_UINT8 *base64_decode(VOS_UINT8 *cipher)
{

    VOS_UINT8 counts = 0;
    VOS_UINT8 buffer[4];
    VOS_UINT8 *plain = malloc(strlen((const char *)cipher) * 3 / 4);
    VOS_UINT32 i = 0, p = 0;

    for (i = 0; cipher[i] != '\0'; i++) {
        char k;
        for (k = 0; k < 64 && base46_map[k] != cipher[i]; k++)
            ;
        buffer[counts++] = k;
        if (counts == 4) {
            plain[p++] = (buffer[0] << 2) + (buffer[1] >> 4);
            if (buffer[2] != 64) {
                plain[p++] = (buffer[1] << 4) + (buffer[2] >> 2);
            }

            if (buffer[3] != 64) {
                plain[p++] = (buffer[2] << 6) + buffer[3];
            }
            counts = 0;
        }
    }

    plain[p] = '\0'; /* string padding character */
    return plain;
}
